// Action.h
//
#ifndef CADTOOL_H
#define CADTOOL_H

//#include "../gui_elements/CustomProxy.h"
#include "OpenGL/Math.h"

#include <map>
#include <string>
#include <vector>

namespace OpenGL{
	class Renderer;
}


class CadEngine;

// Abstract cad tool
class CadTool
{
	friend class CadEngine;

public:
	typedef std::map<std::string, double> Attributes;

protected:
	enum Status { Idle, Drag, Complete };
	
	Status   _status;

	CadEngine *_manager;

	//CadTool   *_nextTool;	// pointer to the next action in the action chain.
	//						// there is no need to call delete because the ownership
	//						// of this object is passed to the manager

	std::string _name;
	int _totPoints;
	int _selIndex;		// index of the selected (working) point [-1 if none]
	int _nPoints;
	bool _waitConfirm;
	bool _completed;
	bool _chained;
	std::vector<OpenGL::Math::dvec3> _points;
	std::vector<bool>	   _pointsLocked;
	Attributes			   _attributes;	// map of current locked attributes.
	std::string            _objectAttributes;	// attributes for the object to be created

	OpenGL::Math::dvec3 _capturedPoint;
	OpenGL::Math::dvec3 _confirmPoint;


	//void nextTool();
	//void clearToolsChain();
	void chainPoint();

	int	 setPoint(const OpenGL::Math::dvec3 &p,bool force = false,int index = -1);
	int	 getClosestPoint(const OpenGL::Math::dvec3 &p);
	void setCompleted(bool b)   {_completed = b;}
	void lockPoint(int index, bool lock);
	void setManager( CadEngine *manager ) { _manager = manager; }
	
	const int SELECTION_THRESHOLD;
	const int COLLAPSE_THRESHOLD;
	const int DISCARD_THRESHOLD;

public:
	CadTool(const std::string &name, int numPoints/*,  CadTool* next = 0*/); 
	virtual ~CadTool();

	// -----------------------------------------------------------------------------------------------
	bool isRunning()		
	{
		return 
		((_status == Idle||_status == Complete) && (_nPoints == _totPoints) )
		|| _waitConfirm
		|| (_nPoints > 0 && _nPoints <= _totPoints);
	}

	bool isChained()										const   { return _chained; }
	bool isCompleted()                                      const	{ return (_status == Complete);}
	bool isPointLocked(int i)								const	{ return i<_nPoints? _pointsLocked[i] : false;}
	bool isAttributeLocked(const std::string &attribName)	const;
	int  getCollectedPointCount()							const	{ return _nPoints; }
	int  getSelectedPointID()								const   { return _selIndex; }
	std::string getName()									const   { return _name; }
	
	std::vector<OpenGL::Math::dvec3> &getPoints()	{ return _points;  }

	void setPointValue( const OpenGL::Math::dvec3 &point,int index );
	void setAttributes( const std::string &attr );
	void setWaitConfirm(bool b)	{_waitConfirm = b;}
	bool isWaitingConfirm()		const {return _waitConfirm;}
	bool confirm(const OpenGL::Math::dvec3 &p);
	void confirm();

	void collectPoint(const OpenGL::Math::dvec3 &p/*, bool firstPointDraggable = false*/);
	void dragPoint(const OpenGL::Math::dvec3 &p/*, bool firstPointDraggable = false*/);
	void done(const OpenGL::Math::dvec3 &p, bool force);
	void done();

	void lockAttribute(const std::string &attribName, double value);
	void unlockAttribute(const std::string &attribName);
	
	virtual void execute()                   = 0;
	virtual void draw( OpenGL::Renderer *r ) = 0;
	virtual bool canHilight() const          = 0;
	virtual bool canSnap() const             = 0;
	virtual bool canStayOnScreen() const     = 0;
	virtual bool canCollectPoints() const     { return _totPoints > 0; }

	virtual void validate(){}
	virtual void updatePreview() {}
	virtual void reset();
};


#endif